class_name Water
extends Node2D

@export var show_water_top_line: bool = true
@export var can_splash: bool = true

@export var water_color: Color
@onready var water_polygon: Polygon2D = $WaterPolygon
@export var water_top_line_color: Color
@onready var line_2d: Line2D = $Line2D

@export var water_width: float = 96
@export var spring_number: int = 6
var distance_between_springs: float = 16
@export var border_curve_bake_interval: float = 2
@export var water_bottom: int = 30

@export var spring_constant: float = 100
@export var dampening: float = 4
@export var spread = 0.3
	
const WATER_SPRING = preload("res://levels/water/water_spring.tscn")
var springs: Array[WaterSpring] = []
var passes = 1
var water_border_curve: Curve2D = Curve2D.new()
var level: Level = null


func _ready() -> void:
	if not show_water_top_line:
		line_2d.visible = false
	
	water_polygon.material = water_polygon.material.duplicate()
	
	var shader_material = water_polygon.material as ShaderMaterial
	shader_material.set_shader_parameter("tint", water_color)
	
	line_2d.default_color = water_top_line_color
	
	level = get_tree().current_scene as Level
	
	distance_between_springs = water_width / (spring_number - 1)
	init_springs()
	
	_physics_process(0)


func init_springs():
	for i in range(spring_number):
		var x_position = distance_between_springs * i
		var inst = WATER_SPRING.instantiate()
		add_child(inst)
		inst.index = i
		inst.position = Vector2(x_position, 0)
		inst.set_collision_width(distance_between_springs)
		inst.splash.connect(splash)
		
		springs.append(inst)
		

func _physics_process(delta: float) -> void:
	for water_spring in springs:
		water_spring.move(spring_constant, dampening, delta)
	
	var left_deltas = []
	var right_deltas = []
	
	#initialize the values with an array of zeros
	for i in range (springs.size()):
		left_deltas.append(0)
		right_deltas.append(0)
	
	for j in range(passes):
		#loops through each spring of our array
		for i in range(springs.size()):
			#adds velocity to the spring to the LEFT of the current spring
			if i > 0:
				left_deltas[i] = spread * (springs[i].height - springs[i-1].height)
				springs[i-1].velocity += left_deltas[i]
			#adds velocity to the spring to the RIGHT of the current spring
			if i < springs.size()-1:
				right_deltas[i] = spread * (springs[i].height - springs[i+1].height)
				springs[i+1].velocity += right_deltas[i]
	
	draw_water_border()
	draw_water_body()


func splash(index, speed):
	if not can_splash: return
	
	var target_spring = springs[index]
	target_spring.velocity += speed
	
	var splash_occur_position = target_spring.get_random_collision_position()
	var current_level = get_tree().current_scene as Level
	current_level.emit_particle("particle_water_splash", splash_occur_position)
	

func draw_water_body():
	var water_polygon_points = water_border_curve.get_baked_points()
	
	var first_index = 0
	var last_index = water_polygon_points.size()-1
	
	water_polygon_points.append(Vector2(water_polygon_points[last_index].x, water_bottom))
	water_polygon_points.append(Vector2(water_polygon_points[first_index].x, water_bottom))
	
	water_polygon_points = PackedVector2Array(water_polygon_points)
	
	water_polygon.set_polygon(water_polygon_points)
	

func draw_water_border():
	var curve = water_border_curve
	
	var surface_points = []
	for i in range(springs.size()):
		surface_points.append(springs[i].position)
	
	curve.clear_points()
	for i in range(surface_points.size()):
		var p = surface_points[i]
		
		# 找前后点
		var prev = surface_points[max(i - 1, 0)]
		var next = surface_points[min(i + 1, surface_points.size() - 1)]

		# 计算方向向量（Catmull-Rom 的近似）
		var dir = (next - prev) * 0.25

		var in_handle = -dir
		var out_handle = dir

		curve.add_point(p, in_handle, out_handle)
		
	curve.bake_interval = border_curve_bake_interval
	var baked_points: PackedVector2Array = curve.get_baked_points()
	line_2d.points = baked_points
	

func get_water_rect():
	return Rect2(global_position, Vector2(water_width, water_bottom))
	
	
